﻿using Microsoft.VisualStudio.TestTools.UnitTesting;
using EF_Model;
using Moq;
using System.Data.Objects;
using System;
using System.Linq;

namespace EF_Tests
{
    [TestClass]
    public class Database_Interaction_Tests
    {
        // read operations //

        [TestMethod]
        public void Child_Object_Is_Searchable_After_InMemory_Add()
        {
            Customer c = new Customer();
            c.CustomerID = "118";
            c.ContactName = "xxx-118";
            c.CompanyName = "com-001";

            Order order = new Order();
            order.OrderDate = DateTime.Now;

            c.Orders.Add(order);
            
            Order order2 = c.Orders.FirstOrDefault(x => x.OrderDate != null);

            Console.WriteLine(order2.OrderDate.ToString());
            Console.WriteLine(order2.OrderID.ToString());

        }

        [TestMethod]
        public void Find_In_Physical_Database()
        {
            DatabaseContext db = new DatabaseContext();
            ObjectSet<Customer> customers = db.CreateObjectSet<Customer>();

            Customer customer = db.Customers.FirstOrDefault(x => x.CustomerID == "001");
            Console.Write(customer.CompanyName);
        }

        [TestMethod]
        public void MockDb_Dont_Find_In_Physical_Database_When_Setup_Method_Is_Not_Specified()
        {
            Mock<DatabaseContext> db = new Mock<DatabaseContext>();
            ObjectSet<Customer> customers = db.Object.CreateObjectSet<Customer>();

            /*
             * db.Object.Customers is null, since this is virtual. 
             * Also ObjectSet<Customer> customers is not connected with db.Object (context)
             * Without a setup method it should throw null reference exception.
            */
            Customer customer = db.Object.Customers.FirstOrDefault(x => x.CustomerID == "001");
            Console.Write(customer.CompanyName);
        }

        [TestMethod]
        public void MockDb_Searches_In_Physical_Database_When_Setup_Method_Is_Specified()
        {
            Mock<DatabaseContext> db = new Mock<DatabaseContext>();
            ObjectSet<Customer> customers = db.Object.CreateObjectSet<Customer>();
            
            db.Setup(x1 => x1.Customers).Returns(customers);

            Customer customer = db.Object.Customers.FirstOrDefault(x => x.CustomerID == "001");
            Console.Write(customer.CompanyName);
        }

        [TestMethod]
        public void Dummy_Read()
        {
            Mock<DatabaseContext> dbContext = new Mock<DatabaseContext>();
            Mock<IObjectSet<Customer>> customers = new Mock<IObjectSet<Customer>>();//db.Object.CreateObjectSet<Customer>() can NOT be used

            dbContext.Setup(db => db.Customers).Returns(customers.Object);

            Console.Write(dbContext.Object.Customers.ToString());//passes
        }

        [TestMethod]
        public void Dummy_Read_XX()
        {
            Mock<DatabaseContext> dbContext = new Mock<DatabaseContext>();
            Mock<IObjectSet<Customer>> customers = new Mock<IObjectSet<Customer>>();//db.Object.CreateObjectSet<Customer>() can NOT be used

            Customer c = new Customer();
            c.CustomerID = "118";
            c.ContactName = "xxx-118";
            c.CompanyName = "com-001";

            customers.Object.AddObject(c);//do nothing!

            dbContext.Setup(db => db.Customers).Returns(customers.Object);

            Customer c1 = dbContext.Object.Customers.First(x => x.CustomerID == "001");
            //Console.Write(dbContext.Object.Customers.ToString());//passes
            Console.Write(c1.ContactName);//passes

        }

        // write operations //
        
        [TestMethod]
        public void Writing_To_Database_Using_Explicit_ObjectSet()
        {
            Customer c = new Customer();
            c.CustomerID = "118";
            c.ContactName = "xxx-118";
            c.CompanyName = "com-001";

            DatabaseContext db = new DatabaseContext();
            ObjectSet<Customer> customerObjectSet = db.CreateObjectSet<Customer>();

            customerObjectSet.AddObject(c);
            db.SaveChanges();
        }

        [TestMethod]
        public void Writing_To_Database_Not_Works_In_Physical_Database_When_Mock_Database_Is_Used()
        {
            Customer c = new Customer();
            c.CustomerID = "118";
            c.ContactName = "xxx-118";
            c.CompanyName = "com-001";

            Mock<DatabaseContext> db = new Mock<DatabaseContext>();
            ObjectSet<Customer> customerObjectSet = db.Object.CreateObjectSet<Customer>();

            customerObjectSet.AddObject(c);
            db.Object.SaveChanges();
        }

        // Dummy Write
        
        [TestMethod]
        public void Dummy_Write_Via_Repository()
        {
            Customer c = new Customer();
            c.CustomerID = "118";
            c.ContactName = "xxx-118";
            c.CompanyName = "com-001";

            Mock<DatabaseContext> dbContext = new Mock<DatabaseContext>();
            Mock<IObjectSet<Customer>> customers = new Mock<IObjectSet<Customer>>();//can also use db.Object.CreateObjectSet<Customer>()
            
            dbContext.Setup(db => db.Customers).Returns(customers.Object);

            CustomerRepository cr = new CustomerRepository(dbContext.Object);

            cr.AddCustomer(c);//passes (actually do nothing internally)
            
            UnitOfWork unitOfWork = new UnitOfWork(dbContext.Object);
            unitOfWork.Commit();//passes (actually do nothing internally)

            //Console.Write(cr.GetById("118").ContactName);//fails, as not searchable
        }
    }
}
